package top.wyloop.fasthome.module.system.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import top.wyloop.fasthome.exception.SystemException;
import top.wyloop.fasthome.logger.ServiceLog;
import top.wyloop.fasthome.logger.SimpleServiceLog;
import top.wyloop.fasthome.module.system.model.entity.User;
import top.wyloop.fasthome.module.system.repository.UserRepository;
import top.wyloop.fasthome.module.system.service.UserService;
import top.wyloop.fasthome.util.DateFormatter;
import top.wyloop.fasthome.util.PasswordUtil;

import java.util.Date;
import java.util.Optional;

/**
 * @author Wyatt6
 * @date 2025/5/9
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {
    private static final String USERNAME_REGEXP = "^[a-zA-Z_0-9]{3,16}$";
    private static final String PASSWORD_REGEXP = "^[a-zA-Z_0-9.~!@#$%^&*?]{6,16}$";

    @Autowired
    private UserRepository userRepository;

    @Override
    @SimpleServiceLog("检查用户名格式服务")
    public boolean checkUsernameFormat(String username) {
        return username.matches(USERNAME_REGEXP);
    }

    @Override
    @SimpleServiceLog("检查密码格式服务")
    public boolean checkPasswordFormat(String password) {
        return password.matches(PASSWORD_REGEXP);
    }

    @Override
    @ServiceLog("创建新用户服务")
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public User createUser(String username, String password) {
        log.info("输入参数: username=[{}]", username);

        log.info("检查用户名是否已被注册");
        if (userRepository.findByUsername(username) != null) {
            throw new SystemException("用户名已被使用");
        }

        log.info("密码加密");
        String salt = PasswordUtil.generateSalt();
        String encryptedPassword = PasswordUtil.encode(password, salt);

        User record = new User();
        record.setUsername(username);
        record.setPassword(encryptedPassword);
        record.setSalt(salt);
        record.setRegisterTime(new Date());
        User user = userRepository.save(record);
        log.info("成功创建新用户: id=[{}]", user.getId());


        // 注意：JPA框架save持久化并不是即时写入数据库的，
        // 因此脱敏是不能在原对象上赋值为null，
        // 否则定义为非空的属性会报错。
        log.info("新用户数据脱敏后返回");
        User result = new User();
        result.setId(user.getId());
        result.setUsername(user.getUsername());
        result.setRegisterTime(user.getRegisterTime());
        return result;
    }

    @Override
    @ServiceLog("身份验证服务")
    public User authentication(String username, String password) {
        log.info("输入参数: username=[{}]", username);

        User user = userRepository.findByUsername(username);
        if (user == null || !user.getPassword().equals(PasswordUtil.encode(password, user.getSalt()))) {
            throw new SystemException("用户名或密码错误");
        }

        log.info("身份验证通过");
        return user;
    }

    @Override
    @ServiceLog("修改密码服务")
    public void changePassword(Long id, String oldPassword, String newPassword) {
        log.info("输入参数: id=[{}]", id);

        Optional<User> oldUser = userRepository.findById(id);
        if (oldUser.isPresent()) {
            log.info("身份验证");
            String oldSalt = oldUser.get().getSalt();
            if (!oldUser.get().getPassword().equals(PasswordUtil.encode(oldPassword, oldSalt))) {
                throw new SystemException("密码错误");
            }

            log.info("新密码加密");
            String salt = PasswordUtil.generateSalt();
            String encryptedPassword = PasswordUtil.encode(newPassword, salt);

            User newUser = oldUser.get();
            newUser.setPassword(encryptedPassword);
            newUser.setSalt(salt);

            log.info("更新数据库记录");
            userRepository.save(newUser);
        } else {
            throw new SystemException("用户不存在");
        }
    }

    @Override
    @ServiceLog("更新用户数据服务(可重复读)")
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public User updateUserAttributesByIdRepeatableRead(User data) {
        Assert.notNull(data, "传入参数为空");
        Assert.notNull(data.getId(), "用户ID为空");

        Long id = data.getId();
        String avatarName = data.getAvatarName();
        Long homeId = data.getHomeId();
        Date registerTime = data.getRegisterTime();
        Date lastLoginTime = data.getLastLoginTime();
        log.info("输入参数: id=[{}]", id);

        Optional<User> oldUser = userRepository.findById(id);
        if (oldUser.isPresent()) {
            User newUser = oldUser.get();

            if (avatarName != null) {
                log.info("设置avatarName=[{}]", avatarName.trim());
                newUser.setAvatarName(avatarName.trim());
            }

            if (homeId != null) {
                log.info("设置homeId=[{}]", homeId);
                newUser.setHomeId(homeId);
            }

            if (registerTime != null) {
                log.info("设置registerTime=[{}]", DateFormatter.commonFormat(registerTime));
                newUser.setRegisterTime(registerTime);
            }

            if (lastLoginTime != null) {
                log.info("设置lastLoginTime=[{}]", DateFormatter.commonFormat(lastLoginTime));
                newUser.setLastLoginTime(lastLoginTime);
            }

            log.info("更新数据库记录");
            userRepository.save(newUser);

            // 注意：JPA框架save持久化并不是即时写入数据库的，
            // 因此脱敏是不能在原对象上赋值为null，
            // 否则定义为非空的属性会报错。
            log.info("新用户数据脱敏后返回");
            User result = new User();
            result.setId(newUser.getId());
            result.setUsername(newUser.getUsername());
            result.setNickname(newUser.getNickname());
            result.setAvatarName(newUser.getAvatarName());
            result.setHomeId(newUser.getHomeId());
            result.setRegisterTime(newUser.getRegisterTime());
            result.setLastLoginTime(newUser.getLastLoginTime());
            return result;
        } else {
            throw new SystemException("用户不存在");
        }
    }

    @Override
    @ServiceLog("更新用户数据服务(序列化)")
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public User updateUserAttributesByIdSerializable(User data) {
        Assert.notNull(data, "传入参数为空");
        Assert.notNull(data.getId(), "用户ID为空");

        Long id = data.getId();
        String username = data.getUsername();
        String nickname = data.getNickname();
        String avatarName = data.getAvatarName();
        Long homeId = data.getHomeId();
        Date registerTime = data.getRegisterTime();
        Date lastLoginTime = data.getLastLoginTime();
        log.info("输入参数: id=[{}]", id);

        Optional<User> oldUser = userRepository.findById(id);
        if (oldUser.isPresent()) {
            User newUser = oldUser.get();

            if (username != null) {
                this.checkUsernameFormat(username.trim());
                log.info("检查用户名是否已被使用");
                if (userRepository.findByUsername(username.trim()) != null) {
                    throw new SystemException("用户名已被使用");
                } else {
                    log.info("设置username=[{}]", username.trim());
                    newUser.setUsername(username.trim());
                }
            }

            if (nickname != null) {
                log.info("检查昵称是否已被使用");
                if (userRepository.findByNickname(nickname.trim()) != null) {
                    throw new SystemException("昵称已被使用");
                } else {
                    log.info("设置nickname=[{}]", nickname.trim());
                    newUser.setNickname(nickname.trim());
                }
            }

            if (avatarName != null) {
                log.info("设置avatarName=[{}]", avatarName.trim());
                newUser.setAvatarName(avatarName.trim());
            }

            if (homeId != null) {
                log.info("设置homeId=[{}]", homeId);
                newUser.setHomeId(homeId);
            }

            if (registerTime != null) {
                log.info("设置registerTime=[{}]", DateFormatter.commonFormat(registerTime));
                newUser.setRegisterTime(registerTime);
            }

            if (lastLoginTime != null) {
                log.info("设置lastLoginTime=[{}]", DateFormatter.commonFormat(lastLoginTime));
                newUser.setLastLoginTime(lastLoginTime);
            }

            log.info("更新数据库记录");
            userRepository.save(newUser);

            // 注意：JPA框架save持久化并不是即时写入数据库的，
            // 因此脱敏是不能在原对象上赋值为null，
            // 否则定义为非空的属性会报错。
            log.info("新用户数据脱敏后返回");
            User result = new User();
            result.setId(newUser.getId());
            result.setUsername(newUser.getUsername());
            result.setNickname(newUser.getNickname());
            result.setAvatarName(newUser.getAvatarName());
            result.setHomeId(newUser.getHomeId());
            result.setRegisterTime(newUser.getRegisterTime());
            result.setLastLoginTime(newUser.getLastLoginTime());
            return result;
        } else {
            throw new SystemException("用户不存在");
        }
    }
}
